use build_migrate::parsers::{Parser, VsParser};
use build_migrate::generators::{Generator, XmakeGenerator};
use build_migrate::core::BuildConfiguration;
use std::path::PathBuf;
use tempfile::tempdir;
use std::fs;

#[test]
fn test_environment_variable_resolution() {
    let parser = VsParser::new();
    
    // 解析包含环境变量的测试项目文件
    let test_file = PathBuf::from("tests/data/test_env_vars.vcxproj");
    let solution = parser.parse(&test_file).expect("应该能够解析测试项目文件");
    
    assert_eq!(solution.projects.len(), 1);
    let project = &solution.projects[0];
    
    // 检查 Debug 配置
    if let Some(debug_settings) = project.configurations.get(&BuildConfiguration::Debug) {
        // 验证包含目录中的环境变量已被解析
        let include_dirs: Vec<String> = debug_settings
            .include_directories
            .iter()
            .map(|p| p.to_string_lossy().to_string())
            .collect();
        
        // 验证包含目录：已知变量被解析，未知变量保持不变
        // $(QTDIR) 现在是未知变量，应该保持不变
        assert!(include_dirs.iter().any(|dir| dir.contains("$(QTDIR)") && dir.contains("include")), 
                "应该包含未解析的$(QTDIR)变量, 实际包含: {:?}", include_dirs);
        
        assert!(include_dirs.iter().any(|dir| dir.contains("include")), 
                "应该包含项目包含目录");
        
        assert!(include_dirs.iter().any(|dir| dir.contains("x64_Debug")), 
                "应该包含解析了平台和配置变量的目录");
        
        // 验证预处理器定义中的环境变量已被解析
        let defines = &debug_settings.preprocessor_definitions;
        assert!(defines.iter().any(|def| def.contains("x64_BUILD")), 
                "应该包含解析了平台变量的预处理器定义, 实际定义: {:?}", defines);
        
        // 验证编译器选项中的环境变量已被解析
        let compiler_flags = &debug_settings.compiler_flags;
        assert!(compiler_flags.iter().any(|flag| flag.contains("Debug_MODE")), 
                "应该包含解析了配置变量的编译器选项, 实际选项: {:?}", compiler_flags);
        
        // 验证库目录中的环境变量已被解析
        let lib_dirs: Vec<String> = debug_settings
            .library_directories
            .iter()
            .map(|p| p.to_string_lossy().to_string())
            .collect();
        
        assert!(lib_dirs.iter().any(|dir| dir.contains("$(QTDIR)") && dir.contains("lib")), 
                "应该包含未解析的Qt库目录变量, 实际库目录: {:?}", lib_dirs);
        
        assert!(lib_dirs.iter().any(|dir| dir.contains("x64_v143_Debug")), 
                "应该包含解析了复合环境变量的库目录, 实际库目录: {:?}", lib_dirs);
        
        // 验证链接库中的环境变量已被解析
        let libraries = &debug_settings.libraries;
        assert!(libraries.iter().any(|lib| lib.contains("x64_Debug")), 
                "应该包含解析了环境变量的库名, 实际库: {:?}", libraries);
        
        // 验证Qt设置
        assert!(debug_settings.qt_settings.enabled, "应该启用Qt");
        assert_eq!(debug_settings.qt_settings.version, Some("5.15.2".to_string()), 
                   "应该正确解析Qt版本");
    } else {
        panic!("未找到Debug配置");
    }
    
    // 检查 Release 配置
    if let Some(release_settings) = project.configurations.get(&BuildConfiguration::Release) {
        // 验证Release配置中的环境变量解析
        let defines = &release_settings.preprocessor_definitions;
        assert!(defines.iter().any(|def| def.contains("x64_BUILD")), 
                "Release配置应该包含解析了平台变量的预处理器定义");
        
        let compiler_flags = &release_settings.compiler_flags;
        assert!(compiler_flags.iter().any(|flag| flag.contains("Release_MODE")), 
                "Release配置应该包含解析了配置变量的编译器选项");
    } else {
        panic!("未找到Release配置");
    }
}

#[test]
fn test_xmake_generation_with_resolved_variables() {
    let parser = VsParser::new();
    let generator = XmakeGenerator::new();
    
    // 解析测试项目
    let test_file = PathBuf::from("tests/data/test_env_vars.vcxproj");
    let solution = parser.parse(&test_file).expect("应该能够解析测试项目文件");
    
    // 生成xmake配置
    let temp_dir = tempdir().expect("应该能创建临时目录");
    let project_root = temp_dir.path();

    let code_style = build_migrate::config::CodeStyleConfig::default();
    generator.generate(&solution, project_root, &code_style).expect("应该能生成xmake.lua");

    let output_file = project_root.join("xmake.lua");
    
    // 读取生成的内容
    let content = fs::read_to_string(&output_file).expect("应该能读取生成的文件");
    
    // 验证生成的xmake.lua包含正确的路径
    assert!(content.contains("add_includedirs"), "应该包含包含目录设置");
    assert!(content.contains("add_linkdirs"), "应该包含链接目录设置");
    assert!(content.contains("add_links"), "应该包含链接库设置");
    assert!(content.contains("add_defines"), "应该包含预处理器定义");
    
    // 验证已知变量被正确解析，未知变量保持不变
    // 注意：$(Configuration)、$(Platform)、$(PlatformToolset) 是已知变量应该被解析
    assert!(!content.contains("$(Configuration)"), "$(Configuration)是已知变量应该被解析");
    assert!(!content.contains("$(Platform)"), "$(Platform)是已知变量应该被解析");
    assert!(!content.contains("$(PlatformToolset)"), "$(PlatformToolset)是已知变量应该被解析");
    
    // $(QTDIR) 如果没有在配置文件中定义，应该保持不变
    // 这取决于测试数据文件中是否配置了 QTDIR
    
    // 验证包含解析后的路径
    assert!(content.contains("qt"), "应该包含解析后的Qt相关路径");
    assert!(content.contains("x64"), "应该包含解析后的平台信息");
    
    println!("生成的xmake.lua内容:\n{}", content);
}

#[test]
fn test_environment_resolver_direct() {
    use build_migrate::environment::EnvironmentResolver;
    use build_migrate::core::BuildConfiguration;
    use tempfile::tempdir;
    
    let temp_dir = tempdir().expect("应该能创建临时目录");
    let resolver = EnvironmentResolver::new(temp_dir.path().to_path_buf());
    
    // 测试未配置的变量保持不变（移除了Qt自动检测后，QTDIR是未知变量）
    let result = resolver.resolve_variables("$(QTDIR)/include", &BuildConfiguration::Debug);
    assert_eq!(result, "$(QTDIR)/include"); // 未知变量应该保持不变
    
    // 测试配置变量解析
    let result = resolver.resolve_variables("$(Configuration)", &BuildConfiguration::Debug);
    assert_eq!(result, "Debug");
    
    let result = resolver.resolve_variables("$(Configuration)", &BuildConfiguration::Release);
    assert_eq!(result, "Release");
    
    // 测试复合变量解析
    let result = resolver.resolve_variables(
        "$(Platform)_$(PlatformToolset)_$(Configuration)", 
        &BuildConfiguration::Debug
    );
    assert_eq!(result, "x64_v143_Debug");
    
    // 测试路径列表解析
    let paths = "$(QTDIR)/include;$(ProjectDir)/src;%(AdditionalIncludeDirectories)";
    let resolved_paths = resolver.resolve_path_list(paths, &BuildConfiguration::Debug);
    
    assert_eq!(resolved_paths.len(), 2); // %(AdditionalIncludeDirectories)应该被过滤掉
    
    let path_strings: Vec<String> = resolved_paths.iter()
        .map(|p| p.to_string_lossy().to_string())
        .collect();
    
    // $(QTDIR) 保持不变，$(ProjectDir) 解析为 "."
    assert!(path_strings.iter().any(|p| p.contains("$(QTDIR)") && p.contains("include")));
    assert!(path_strings.iter().any(|p| p.contains("src") && (p.contains(".") || p.contains("./") || p.contains(".\\"))));
}

#[test]
fn test_all_release_lib_paths_scenario() {
    use build_migrate::environment::EnvironmentResolver;
    use build_migrate::core::BuildConfiguration;
    use tempfile::tempdir;
    
    let temp_dir = tempdir().expect("应该能创建临时目录");
    let mut resolver = EnvironmentResolver::new(temp_dir.path().to_path_buf());
    
    // 模拟 Visual Studio 中的 AllReleaseLibPaths 环境变量
    // 通常包含多个库路径，按分号分隔
    resolver.set_variable("AllReleaseLibPaths", 
        "C:/Program Files/Microsoft Visual Studio/lib;C:/Windows/System32;D:/ThirdParty/libs".to_string());
    
    // 模拟 vcxproj 文件中的 AdditionalLibraryDirectories 设置
    let lib_dirs = "$(QTDIR)\\lib;$(AllReleaseLibPaths);%(AdditionalLibraryDirectories)";
    
    let result = resolver.resolve_path_list(lib_dirs, &BuildConfiguration::Release);
    
    // 应该得到 4 个有效路径 (QTDIR/lib 保持不变，AllReleaseLibPaths 的 3 个路径)
    // %(AdditionalLibraryDirectories) 应该被过滤掉
    assert_eq!(result.len(), 4);
    
    let path_strings: Vec<String> = result.iter()
        .map(|p| p.to_string_lossy().to_string())
        .collect();
    
    // 验证各个路径都正确解析
    assert!(path_strings.iter().any(|p| p.contains("$(QTDIR)") && p.contains("lib")), 
            "应该保留未知环境变量 QTDIR");
    assert!(path_strings.iter().any(|p| p.contains("Microsoft Visual Studio") && p.contains("lib")), 
            "应该包含 Visual Studio 库路径");
    assert!(path_strings.iter().any(|p| p.contains("System32")), 
            "应该包含 System32 路径");
    assert!(path_strings.iter().any(|p| p.contains("ThirdParty") && p.contains("libs")), 
            "应该包含第三方库路径");
    assert!(!path_strings.iter().any(|p| p.contains("%(")), 
            "不应该包含 VS 宏语法");
    
    println!("解析结果: {:?}", path_strings);
}
